const path = require('path');
const jschemator = require('jschemator');

let generatePath;
if (process.env.GENERATE_PATH) {
    generatePath = process.env.GENERATE_PATH;
} else {
    generatePath = path.resolve(process.env.HOME || process.env.USERPROFILE, 'pdf-service-generate');
}

exports.generateBasePath = generatePath;

exports.generatePath = function (filename = Date.now(), ext = 'pdf') {
    const date = new Date();
    return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}/${filename}.${ext}`;
}

const common = {
    waitFor: {type: 'string'},
    waitForError: {type: 'string'},
    timeout: {type: 'integer', minimum: 5000},
    waitUntil: {
        type: ['string', 'array'],
        items: {type: 'string'},
        minItems: 1
    }
};

const viewport = {
    type: 'object',
    properties: {
        width: {type: 'integer'}, // 设备宽度像素
        height: {type: 'integer'}, // 设备高度像素
        deviceScaleFactor: {type: 'integer'} // 设备缩放 dpr，默认1
    }
}

// @see https://github.com/ajv-validator/ajv/blob/master/KEYWORDS.md
const generatePdfParamSchema = createSchema({
    type: "object",
    properties: {
        pages: {
            type: 'array',
            items: {
                type: ['string', 'object'],
                properties: {
                    url: {type: 'string', format: 'url'},
                    ...common,
                    viewport,
                    pdfOption: {
                        type: 'object',
                        properties: {
                            displayHeaderFooter: {type: 'boolean'},
                            headerTemplate: {type: 'string'},
                            footerTemplate: {type: 'string'},
                            printBackground: {type: 'boolean'},
                            landscape: {type: 'boolean'},
                            format: {type: 'string'},
                            margin: {
                                type: 'object',
                                properties: {
                                    top: {type: 'string'},
                                    right: {type: 'string'},
                                    bottom: {type: 'string'},
                                    left: {type: 'string'},
                                },
                                additionalProperties: false
                            }
                        },
                        additionalProperties: false
                    }
                },
                required: ['url'],
            },
            minItems: 1
        },
        proxy: {type: 'string'},
        ...common,
        viewport
    },
    required: ['pages']
});

exports.validateGeneratePdfParam = function (pages) {
    validate(generatePdfParamSchema, pages);
}

const generateImgParamSchema = createSchema({
    type: "object",
    properties: {
        pages: {
            type: 'array',
            items: {
                type: ['string', 'object'],
                properties: {
                    url: {type: 'string', format: 'url'},
                    ...common,
                    viewport,
                    imgOption: {
                        type: 'object',
                        properties: {
                            type: {type: 'string', enum: ['png', 'jpeg', 'jpg']},
                            quality: {type: 'number', minimum: 0, maximum: 100},
                            fullPage: {type: 'boolean'},
                            clip: {
                                type: 'object',
                                properties: {
                                    x: {type: 'integer'},
                                    y: {type: 'integer'},
                                    width: {type: 'integer', minimum: 0},
                                    height: {type: 'integer', minimum: 0},
                                },
                            },
                            screenshotSelector: {type: 'string'},
                        },
                        additionalProperties: false
                    }
                },
                required: ['url'],
            },
            minItems: 1
        },
        proxy: {type: 'string'},
        ...common,
        viewport
    },
    required: ['pages']
});

exports.validateGenerateImgParam = function (pages) {
    validate(generateImgParamSchema, pages);
}

const mergePdfParamSchema = createSchema({
    type: 'object',
    properties: {
        pdfPaths: {
            type: "array",
            items: {type: "string"},
            minItems: 2
        },
        oddPageAutoInsertBlank: {type: 'boolean'}
    },
    required: ['pdfPaths']
});

exports.validateMergePdfParam = function (pdfs) {
    validate(mergePdfParamSchema, pdfs);
}

const splitPdfParamSchema = createSchema({
    type: 'object',
    properties: {
        pdfPath: {type: "string"}
    }
});
exports.validateSplitPdfParam = function (pdfs) {
    validate(splitPdfParamSchema, pdfs);
}

function validate(validateSchema, mod) {
    const valid = validateSchema.validate(mod);
    const [key] = validateSchema.paths || [];
    if (!valid) {
        if (key && validateSchema.errors[key]) {
            throw new Error(`${key} : ${validateSchema.errors[key].message}`);
        } else {
            var props = getAdditionalProp(validateSchema.schema, mod);
            if (props.length) {
                throw new Error(`意外的出现了下面属性 : ${props.join('；')}`);
            }
        }
    }
}

function createSchema(schema) {
    return jschemator(schema, 'zh', {flat: true, allErrors: false});
}

// 获取 schema 描述中，意外出现的其它属性
function getAdditionalProp(schema, model, keys = [], parent = '') {
    if (!schema || !schema.properties || !model) {
        return keys;
    }
    Object.keys(model).forEach(key => {
        const prop = schema.properties[key];
        if (!prop) {
            keys.push(parent + key);
        } else if (prop.type === 'object') {
            getAdditionalProp(prop, model[key], keys, parent + key + '.');
        } else if (prop.type === 'array') {
            if (prop.items && prop.items.type === 'object') {
                model[key].forEach((o, i) => {
                    getAdditionalProp(prop.items, o, keys, parent + key + `[${i}].`)
                });
            }
        }
    });
    return keys;
}
